/*
 * AdjacencyMatrix.hpp
 *
 *  Created on: 11 lis 2013
 *      Author: dawid.wysakowicz
 */

#ifndef ADJACENCYMATRIX_HPP_
#define ADJACENCYMATRIX_HPP_

#include <vector>
#include <ostream>
#include <algorithm>

namespace common {
template <class T> class Matrix;
}  // namespace common

template<class T>
std::ostream& operator<<(std::ostream&, const common::Matrix<T>&);


namespace common
{

template<class T>
class Matrix
{
public:
	friend std::ostream& operator<< <>(std::ostream&, const Matrix<T>&);
	Matrix(size_t rows, size_t columns);
	virtual ~Matrix();

	size_t rowsSize();
	size_t columsSize();

	T& operator() (size_t row, size_t column);
	T operator() (size_t row, size_t column) const;
private:
	std::vector<std::vector<int>> matrix_;
};

template<class T>
inline Matrix<T>::Matrix(size_t rows, size_t columns)
{
	matrix_.resize(rows, std::vector<T>(columns, T()));
}

template<class T>
inline Matrix<T>::~Matrix()
{
}

template<class T>
inline T& Matrix<T>::operator ()(size_t row, size_t column)
{
	return matrix_.at(row).at(column);
}

template<class T>
inline size_t Matrix<T>::rowsSize()
{
	return matrix_.size();
}

template<class T>
inline size_t Matrix<T>::columsSize()
{
	return matrix_.at(0).size();
}

template<class T>
inline T Matrix<T>::operator ()(size_t row, size_t column) const
{
	return matrix_.at(row).at(column);
}
} /* namespace common */

template<class T>
std::ostream& operator<< (std::ostream& stream, const common::Matrix<T>& matrix)
{
	size_t currentRow = 0;
	std::for_each(matrix.matrix_.begin(), matrix.matrix_.end(),
			[&](const std::vector<int>& column)
			{
				size_t currentColumn = 0;
				std::for_each(column.begin(), column.end(),
					[&](int x)
							{
								if (x > 0)
								{	stream << currentRow << "->" << currentColumn << " : " << x << std::endl;};
								++currentColumn;
							});
				++currentRow;
			});

	return stream;
}

#endif /* ADJACENCYMATRIX_HPP_ */
